# -*- Mode: makefile -*-

# Makefile for the cil wrapper
# @do_not_edit@ Makefile.in
#
# authors: George Necula, Gabriel Kerneis

CILLY			  = cilly

.PHONY: all
all: cillib $(CILLY)

# Now add the defines for the CIL features
include Makefile.features

# look out for outdated Makefile; if it's out of date, this will automatically
# re-run ./config.status, then re-exec make with the same arguments
Makefile: config.status Makefile.in
	./$<

config.status: configure
	./$@ --recheck

$(srcdir)/configure: configure.ac aclocal.m4
	cd '$(srcdir)' && autoconf

# autoheader might not change config.h.in, so touch a stamp file.
$(srcdir)/config.h.in: stamp-h.in
$(srcdir)/stamp-h.in: configure.ac aclocal.m4
	cd '$(srcdir)' && autoheader
	echo timestamp > '$(srcdir)/stamp-h.in'

config.h: stamp-h
stamp-h: config.h.in config.status
	./config.status

@DEFAULT_COMPILER@=1

ifndef EMUL
   EMUL=@EMUL@
endif
ifdef EMUL
	 # Compile machdep-ml.c with -static when
	 # cross-compiling only (because -static
	 # is broken on MacOS X)
   MACHDEPCC=$(CC) $(CFLAGS) -static -D_GNUCC
else
   MACHDEPCC=gcc -D_GNUCC
endif

# We have to use _build because of OCaml's bug #0004502
OBJDIR      = _build
BINDIR		  = bin
CILLYDIR	  = lib

OCAMLBEST = @OCAMLBEST@
CILLIB_FILES = $(OBJDIR)/src/cil.cma
ifeq ($(OCAMLBEST),opt)
 CILLIB_FILES  += $(OBJDIR)/src/cil.cmxa $(OBJDIR)/src/cil.a
 EXEMODE        = .native
else
 EXEMODE        = .byte
endif

EXE = $(EXEMODE)$(EXEEXT)

OCAMLBUILD = @OCAMLBUILD@
OCAMLBUILD += -build-dir $(OBJDIR) -no-links -classic-display

OCAMLFIND = @OCAMLFIND@

PERL = @PERL@

# Force to always rebuild a target (for ocamlbuild targets)
.PHONY: .FORCE
.FORCE:

$(OBJDIR)/src/%: .FORCE
	$(OCAMLBUILD) src/$*

$(OBJDIR)/doc/%: .FORCE
	CIL_VERSION=@CIL_VERSION@ $(OCAMLBUILD) doc/$*

# OCaml CIL library
.PHONY: cillib
cillib: $(CILLIB_FILES) $(OBJDIR)/src/cil.libfiles

# cilly main executable
$(BINDIR)/$(CILLY)$(EXE): $(OBJDIR)/src/main$(EXEMODE)
	cp $< $@

# cilly perl wrapper
prefix = @prefix@

FORCE_PERL_PREFIX = @FORCE_PERL_PREFIX@
ifeq ($(FORCE_PERL_PREFIX), 1)
	PERL_MM_OPT = INSTALL_BASE="$(prefix)"
	export PERL_MM_OPT
endif

CILLYMOD := Cilly

$(CILLYDIR)/Makefile: Makefile $(CILLYDIR)/Makefile.PL $(CILLYDIR)/App/$(CILLYMOD).pm
	cd $(CILLYDIR); $(PERL) Makefile.PL

.PHONY: $(CILLY)
$(CILLY): $(BINDIR)/$(CILLY)$(EXE) $(CILLYDIR)/Makefile
	$(MAKE) -C $(CILLYDIR)

# Create the machine dependency module
# If the cl command cannot be run then the MSVC part will be identical to GCC
.PHONY : machdep
machdep: $(OBJDIR)/machdep.ml
$(OBJDIR)/machdep.ml : src/machdep-ml.c configure.ac Makefile.in
	@rm -f $@
	@mkdir -p $(OBJDIR)
	@echo "(* This module was generated automatically by code in Makefile and $(<F) *)" >$@
	@echo "type mach = {" >> $@
	@echo "  version_major: int;     (* Major version number *)"    >> $@
	@echo "  version_minor: int;     (* Minor version number *)"    >> $@
	@echo "  version: string;        (* gcc version string *)"      >> $@
	@echo "  underscore_name: bool;  (* If assembly names have leading underscore *)" >> $@
	@echo "  sizeof_short: int;      (* Size of \"short\" *)"       >> $@
	@echo "  sizeof_int: int;        (* Size of \"int\" *)"         >> $@
	@echo "  sizeof_bool: int;       (* Size of \"_Bool\" *)"       >> $@
	@echo "  sizeof_long: int ;      (* Size of \"long\" *)"        >> $@
	@echo "  sizeof_longlong: int;   (* Size of \"long long\" *)"   >> $@
	@echo "  sizeof_ptr: int;        (* Size of pointers *)"        >> $@
	@echo "  sizeof_float: int;      (* Size of \"float\" *)"       >> $@
	@echo "  sizeof_double: int;     (* Size of \"double\" *)"      >> $@
	@echo "  sizeof_longdouble: int; (* Size of \"long double\" *)" >> $@
	@echo "  sizeof_void: int;       (* Size of \"void\" *)"        >> $@
	@echo "  sizeof_fun: int;        (* Size of function *)"        >> $@
	@echo "  size_t: string;         (* Type of \"sizeof(T)\" *)"   >> $@
	@echo "  wchar_t: string;        (* Type of \"wchar_t\" *)"     >> $@
	@echo "  alignof_short: int;     (* Alignment of \"short\" *)"  >> $@
	@echo "  alignof_int: int;       (* Alignment of \"int\" *)"    >> $@
	@echo "  alignof_bool: int;      (* Alignment of \"_Bool\" *)"    >> $@
	@echo "  alignof_long: int;      (* Alignment of \"long\" *)"   >> $@
	@echo "  alignof_longlong: int;  (* Alignment of \"long long\" *)" >> $@
	@echo "  alignof_ptr: int;       (* Alignment of pointers *)"   >> $@
	@echo "  alignof_enum: int;      (* Alignment of enum types *)" >> $@
	@echo "  alignof_float: int;     (* Alignment of \"float\" *)"  >> $@
	@echo "  alignof_double: int;    (* Alignment of \"double\" *)" >> $@
	@echo "  alignof_longdouble: int;  (* Alignment of \"long double\" *)" >> $@
	@echo "  alignof_str: int;       (* Alignment of strings *)" >> $@
	@echo "  alignof_fun: int;       (* Alignment of function *)" >> $@
	@echo "  alignof_aligned: int;   (* Alignment of anything with the \"aligned\" attribute *)" >> $@
	@echo "  char_is_unsigned: bool; (* Whether \"char\" is unsigned *)">> $@
	@echo "  const_string_literals: bool; (* Whether string literals have const chars *)">> $@
	@echo "  little_endian: bool; (* whether the machine is little endian *)">>$@
	@echo "  __thread_is_keyword: bool; (* whether __thread is a keyword *)">>$@
	@echo "  __builtin_va_list: bool; (* whether __builtin_va_list is builtin (gccism) *)">>$@
	@echo "}" >> $@ 	
	@if $(MACHDEPCC) $< -o $(OBJDIR)/machdep-ml.exe ;then \
	    echo "machdep-ml.exe created succesfully." \
	;else \
            rm -f $@; exit 1 \
        ;fi
	@echo "let gcc = {" >>$@
	@$(EMUL) $(OBJDIR)/machdep-ml.exe >>$@
	@echo "}"          >>$@
	@if cl -D_MSVC $< -Fe$(OBJDIR)/machdep-ml.exe -Fo$(OBJDIR)/machdep-ml.obj ;then \
           echo "let hasMSVC = true" >>$@ ;\
	         echo "let msvc = {" >>$@ ;\
	           $(OBJDIR)/machdep-ml.exe >>$@ ;\
	         echo "}"          >>$@ \
        ;else \
           echo "let hasMSVC = false" >>$@ ;\
					 echo "let msvc = gcc" >> $@ \
			  ;fi
	@echo "let theMachine : mach ref = ref gcc" >>$@

$(CILLYDIR)/App/$(CILLYMOD).pm: $(CILLYDIR)/App/$(CILLYMOD).pm.in src/machdep-ml.c configure.ac Makefile.in
	cp $(CILLYDIR)/App/$(CILLYMOD).pm.in $(CILLYDIR)/App/$(CILLYMOD).pm
	sed -e "s|CIL_VERSION|@CIL_VERSION@|" $(CILLYDIR)/App/$(CILLYMOD).pm > $(CILLYDIR)/App/$(CILLYMOD).pm.tmp; \
	mv $(CILLYDIR)/App/$(CILLYMOD).pm.tmp $(CILLYDIR)/App/$(CILLYMOD).pm; \
	if $(MACHDEPCC) -m32 src/machdep-ml.c -o $(OBJDIR)/machdep-ml32.exe ;then \
	  sed -e "s|nogcc32model|`$(EMUL) $(OBJDIR)/machdep-ml32.exe --env`|" $(CILLYDIR)/App/$(CILLYMOD).pm > $(CILLYDIR)/App/$(CILLYMOD).pm.tmp; \
	  mv $(CILLYDIR)/App/$(CILLYMOD).pm.tmp $(CILLYDIR)/App/$(CILLYMOD).pm; \
	fi
	if $(MACHDEPCC) -m64 src/machdep-ml.c -o $(OBJDIR)/machdep-ml64.exe ;then \
	  sed -e "s|nogcc64model|`$(EMUL) $(OBJDIR)/machdep-ml64.exe --env`|" $(CILLYDIR)/App/$(CILLYMOD).pm > $(CILLYDIR)/App/$(CILLYMOD).pm.tmp; \
	  mv $(CILLYDIR)/App/$(CILLYMOD).pm.tmp $(CILLYDIR)/App/$(CILLYMOD).pm; \
	fi

.PHONY: cilversion
cilversion: $(OBJDIR)/cilversion.ml
$(OBJDIR)/cilversion.ml: src/cilversion.ml.in config.status
	rm -f $@
	./config.status --file=$@:$<

.PHONY: feature_config
feature_config: $(OBJDIR)/feature_config.ml
$(OBJDIR)/feature_config.ml: config.status
	rm -f $(OBJDIR)/feature_config.*
	echo "(* This module was generated automatically by code in Makefile.in *)" >$@
	echo "open Cil"   >>$@
	echo "let features : featureDescr list = [" >> $@
ifdef USE_BLOCKINGGRAPH
	echo "   Blockinggraph.feature;" >> $@
endif
ifdef USE_RAND
	echo "   Rand.feature;" >> $@
endif
ifdef USE_ARITHABS
	echo "   Arithabs.feature;" >>$@
endif
ifdef USE_ZRAPP
	echo "   Zrapp.feature;" >> $@
endif
ifdef USE_LLVM
	echo "   Llvm.feature;" >> $@
endif
	echo " (* EXTRAFEATURES: *)" >> $@
	echo \
          $(foreach f,@EXTRAFEATURES@, \
             "\n   "`echo $f | cut -c 1 | tr "[a-z]" "[A-Z]"``echo $f | cut -c 2-`".feature;") \
	| $(PERL) -pe 's/\\n/\n/g' >> $@
	echo "]"   >>$@

### DOCUMENTATION

# You should usually run this twice to get all of the references linked
# correctly.
.PHONY: doc
doc: texdoc pdfdoc odoc

.PHONY: odoc texdoc pdfdoc

# Documentation generated by "ocamldoc"
odoc: $(OBJDIR)/doc/cil.docdir/index.html
	-rm -rf doc/html/cil/api
	-mkdir -p doc/html/cil/
	-cp -r $(dir $<) doc/html/cil/api

doc/cilpp.tex: doc/cilcode.pl doc/cil.tex $(CILLYDIR)/App/$(CILLYMOD).pm
	-rm -rf doc/html/cil
	-mkdir -p doc/html/cil
	-mkdir -p doc/html/cil/examples
	cd doc; $(PERL) cilcode.pl cil.tex >cilpp.tex.tmp
	mv doc/cilpp.tex.tmp $@

# Documentation generated from latex files using "hevea"
texdoc: doc/cilpp.tex
	cd doc/html/cil; printf '\\def\\cilversion{@CIL_VERSION@}\n' >cil.version.tex
	cd doc/html/cil; hevea -exec xxdate.exe ../../cilpp
	cd doc/html/cil; hevea -exec xxdate.exe ../../cilpp
	cd doc/html/cil; mv cilpp.html cil.html
	cd doc/html/cil; hacha -o ciltoc.html cil.html
	cp -f doc/index.html doc/html/cil/index.html
	cp -f doc/header.html doc/html/cil

pdfdoc: doc/cilpp.tex
	cd doc; printf '\\def\\cilversion{@CIL_VERSION@}\n' >cil.version.tex
	cd doc; pdflatex cilpp.tex; pdflatex cilpp.tex
	cd doc; mv cilpp.pdf html/cil/CIL.pdf

.PHONY: distclean clean
distclean: clean
	$(MAKE) -C test distclean
	rm -rf autom4te.cache/
	rm -f Makefile
	rm -f $(CILLYDIR)/App/$(CILLYMOD)/CilConfig.pm
	rm -f config.h
	rm -f config.log
	rm -f config.mk
	rm -f config.status
	rm -f doc/header.html
	rm -f doc/index.html
	rm -f src/machdep-ml.c
	rm -f stamp-h

clean: $(CILLYDIR)/Makefile
	rm -rf $(OBJDIR)
	rm -f $(BINDIR)/$(CILLY).*
	rm -rf doc/html/
	rm -rf doc/cilcode.tmp/
	rm -f doc/cil.version.*
	rm -f doc/cilpp.*
	$(MAKE) -C $(CILLYDIR) clean
	rm -f $(CILLYDIR)/App/$(CILLYMOD).pm
	rm -f $(CILLYDIR)/Makefile.old
	rm -f Makefile.features

.PHONY: test
test:
	cd test; ./testcil -r --regrtest

########################################################################

INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@

exec_prefix = @exec_prefix@
datarootdir = @datarootdir@
bindir = @bindir@

install: $(CILLY) install-findlib
	$(MAKE) -C $(CILLYDIR) pure_install
	$(INSTALL) -m 0755 $(BINDIR)/$(CILLY).* $(DESTDIR)$(bindir)

uninstall: $(CILLYDIR)/Makefile uninstall-findlib
	-rm -f $(DESTDIR)$(bindir)/$(CILLY).*
	$(MAKE) -C $(CILLYDIR) force_uninstall

.PHONY: install-findlib uninstall-findlib

install-findlib: cillib uninstall-findlib
	$(OCAMLFIND) install -patch-version @CIL_VERSION@ cil META $(CILLIB_FILES) `cat $(OBJDIR)/src/cil.libfiles`

uninstall-findlib:
	$(OCAMLFIND) remove cil
